package parser;
import java.util.*;
import java.io.*; 
import antlr.RecognitionException;
import antlr.Token;

public class Function {
    
    static final int STANDARD = 0;
    static final int TUPLE = 4;
    static final int DICT = 8;
    static final int GENERATOR = 512;
    static final int ESCAPES = 1024;
    static final int NO_DELETES = 8192;
    
    Function(int name, List parameters, Stmt suite, int[] localNames, boolean is_closure) {
        this.kind = STANDARD;
        int last = parameters.size()-1;
        if (last >= 0 && parameters.get(last) instanceof DictParameter) {
            this.kind |= DICT;
            last--;
        }
        if (last >= 0 && parameters.get(last) instanceof TupleParameter) {
            this.kind |= TUPLE;
        }
        if (suite.yields)
            this.kind |= GENERATOR;
        if (!suite.deletes)
            this.kind |= NO_DELETES;
        if (is_closure)
            this.kind |= ESCAPES;
        this.name = name;
        this.parameters = parameters;
        this.suite = suite;
        this.localNames = localNames;
    }
    
    int name;
    List parameters;
    Stmt suite;
    int[] localNames;
    int kind;
    
    void dump(PrintStream out, Disassembler d) throws RecognitionException {
        out.println("Function " + d.name(name));
        out.println(parameters.size() + " parameters");
        out.println("Locals: " + localNames.length);
        out.println("Kind: " + kind);
        if (suite != null) {
            out.println("Byte Codes:");
            d.dumpCode(suite, out); 
        } else {
            out.println("Native");
        }
        out.println("Local names:");
        int index = 0;
        for (int n : localNames) {
            out.println("" + (index++) + ": " + d.name(n));
        }
    }
    
    void write(ByteStream out) throws RecognitionException {
        out.writeShort(name);
        out.writeShort(kind);
        if ((this.kind & ESCAPES) != 0)
            out.writeShort(parameters.size()+1);
        else
            out.writeShort(parameters.size());
        out.writeShort(localNames.length);
        int patch = out.here();
        out.writeShort(0); 
        out.clearLineNumbers();
        if (suite != null) {
            suite.write(out);
            int offset = out.here()-patch-2;
            if ((offset & 1) != 0)
                out.write(0);
            out.patchShort(patch, offset);
        }
        for (int n : localNames) {
            out.writeShort(n);
        }
    }
    
}
